
mult = [[1,  0,  0, -1, -1,  0,  0,  1],
        [0,  1, -1,  0,  0, -1,  1,  0],
        [0,  1,  1,  0,  0, -1, -1,  0],
        [1,  0,  0,  1, -1,  0,  0, -1]]
        
def cast_light(src, cx, cy, row, start, end, radius, xx, xy, yx, yy, id):
#def cast_light(src, row, start, end, radius, xx, xy, yx, yy, id):
    "Recursive lightcasting function"
    if start < end:
        return
    radius_squared = radius * radius
    for j in range(row, radius + 1):
        dx, dy = -j-1, -j
        blocked = False
        while dx <= 0:
            dx += 1
            # Translate the dx, dy coordinates into map coordinates:
            x, y = cx + dx * xx + dy * xy, cy + dx * yx + dy * yy
            # l_slope and r_slope store the slopes of the left and right
            # extremities of the square we're considering:
            l_slope, r_slope = (dx-0.5) / (dy + 0.5), (dx + 0.5) / (dy-0.5)
            if start < r_slope:
                continue
            elif end > l_slope:
                break
            else:
                # Our light beam is touching this square; light it:
                if dx * dx + dy * dy < radius_squared:
                    src.tiles[x][y].visible = 'full'
                if blocked:
                    # we're scanning a row of blocked squares:
                    if src.tiles[x][y].is_light_blocked():
                        new_start = r_slope
                        continue
                    else:
                        blocked = False
                        start = new_start
                else:
                    if src.tiles[x][y].is_light_blocked() and j < radius:
                        # This is a blocking square, start a child scan:
                        blocked = True
                        cast_light(src, cx, cy, j + 1, start, l_slope,
                                         radius, xx, xy, yx, yy, id + 1)
                        new_start = r_slope
        # Row is scanned; do next row unless last square was blocked:
        if blocked:
            break

def do_fov(level, src, radius, octs=''):
    "Calculate lit squares from the given location and radius"
    octs = _switch(octs)
    #octs =

    for oct in octs:
        cast_light(level, src[0], src[1], 1, 1.0, 0.0, radius,
                         mult[0][oct], mult[1][oct],
                         mult[2][oct], mult[3][oct], oct)

    level.set_lit(src[0], src[1], 0)

def _switch(o):
    if o == 'n':
        return [1,6]
    if o == 'e':
        return [4,7]
    if o == 's':
        return [2,5]
    if o == 'w':
        return [0,3]
    if o == 'ne':
        return [6,7]
    if o == 'se':
        return [4,5]
    if o == 'sw':
        return [2,3]
    if o == 'nw':
        return [0,1]
    return [0,1,2,3,4,5,6,7]